package server;

import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 服务器端
 * 
 * @author
 *
 */
@SuppressWarnings("serial")
public class TankServer extends Frame {

	/**
	 * id号的初始序列
	 */
	public static int ID = 100;
	/**
	 * TCP端口号
	 */
	public static final int TCP_PORT = 2021;
	/**
	 * 转发客户端数据的UDP端口号
	 */
	public static final int UDP_PORT = 2022;
	/**
	 * 客户端集合
	 */
	private List<Client> clients = new ArrayList<>();
	/**
	 * 服务器具象化
	 */
	private Image offScreenImage = null;

	private static final int SERVER_HEIGHT = 300;
	private static final int SERVER_WIDTH = 300;

	public static void main(String[] args) {

		TankServer ts = new TankServer();
		ts.launchFrame();
		ts.start();
	}
	@SuppressWarnings("resource")
	public void start() {
		// 启动一个UDP线程，接收客户端的消息

		Thread t1 = new UdpThread();
		t1.start();
		// 主线程当作TCP线程
		ServerSocket serverSocket = null;
		try {
			serverSocket = new ServerSocket(TCP_PORT);
		} catch (IOException e) {
			e.printStackTrace();
		}

		while (true) {
			Socket socket = null;
			try {
				socket = serverSocket.accept();
				DataInputStream dis = new DataInputStream(socket.getInputStream());
				String ip = socket.getInetAddress().getHostAddress();
				int udpPort = dis.readInt();
				// 接受客户端的连接，将客户端将来用于传递信息的端口号传递过来
				Client client = new Client(ip, udpPort);
				clients.add(client);
				DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
				// 为客户端发送一个ID，此ID逐渐增大
				dos.writeInt(ID++);
				System.out.println("A Client Connect!  Addr- " + socket.getInetAddress() + ":" + socket.getPort()
						+ "----UDP Port" + udpPort);
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				if (socket != null) {
					try {
						socket.close();
						socket = null;
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}

		}

	}

	private class Client {
		String ip;
		//String tankId;
		int udpPort;

		public Client(String ip, int udpPort) {
			this.ip = ip;
			//this.tankId = tankId;
			this.udpPort = udpPort;
		}
	}

	private class UdpThread extends Thread {

		// 用来接收客户端数据的数组
		byte[] buffer = new byte[1024];

		@Override
		// 开启一个UDP线程，不断地进行监听，接收客户端发送来的数据，再传送到其他的客户端
		public void run() {
			DatagramSocket ds = null;
			try {
				// 从UDP端口接受一个包的数据
				ds = new DatagramSocket(UDP_PORT);
			} catch (SocketException e) {
				e.printStackTrace();
			}
			System.out.println("UDP thread started at port :" + UDP_PORT);

			// 只要端口建立起来，就可以传输客户端的数据了
			while (ds != null) {
				// 我们有了一个1024字节的包
				DatagramPacket dp = new DatagramPacket(buffer, buffer.length);
				try {
					// 一旦拿到了一包数据
					ds.receive(dp);
					// 将数据转发到其他的客户端
					for (int i = 0; i < clients.size(); i++) {
						Client client = clients.get(i);
						@SuppressWarnings("unused")
						String ip = client.ip;
						// 将数据发给每个主机从主机列表中抽出IP地址和端口号
						dp.setSocketAddress(new InetSocketAddress(client.ip, client.udpPort));
						// 发送
						ds.send(dp);
					}
					System.out.println("a packet receive!");
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

	}

	//服务器的可视化
	@Override
	public void paint(Graphics g) {
		g.drawString("TankSever has Found !", 85, 60);
		g.drawString("Play With Your Friend Now !", 70, 90);

		InetAddress addr = null;
		try {
			// 抓取当作服务器的主机的IP地址
			addr = InetAddress.getLocalHost();
		} catch (UnknownHostException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
		g.drawString("Server Address: " + addr.getHostAddress(), 60, 120);
		g.drawString("How to play: ", 60, 150);
		g.drawString("在客户端连接上方IP地址即可连接到服务器", 40, 180);
		g.drawString("！！请确保客户端udp端口号各不相同！！", 40, 200);

	}

	@Override
	public void update(Graphics g) {
		if (offScreenImage == null) {
			offScreenImage = this.createImage(SERVER_WIDTH, SERVER_HEIGHT);
		}
		Graphics gOffScreen = offScreenImage.getGraphics();
		Color c = gOffScreen.getColor();
		gOffScreen.setColor(Color.WHITE);
		gOffScreen.fillRect(0, 0, SERVER_WIDTH, SERVER_HEIGHT);
		gOffScreen.setColor(c);
		paint(gOffScreen);
		g.drawImage(offScreenImage, 0, 0, null);
	}

	public void launchFrame() {
		this.setLocation(200, 100);
		this.setSize(SERVER_WIDTH, SERVER_HEIGHT);
		this.setTitle("TankServer");
		this.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
		this.setResizable(false);
		this.setBackground(Color.WHITE);
		this.setVisible(true);
	}

}
